package com.qp.bookkeeping.business.book.service.impl;

import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.qp.bookkeeping.business.book.mapper.BookMapper;
import com.qp.bookkeeping.business.book.mapper.ColumnMapper;
import com.qp.bookkeeping.business.book.mapper.UserMapper;
import com.qp.bookkeeping.business.book.model.Bo.QueryBookBo;
import com.qp.bookkeeping.business.book.model.Bo.StatisticMonthBo;
import com.qp.bookkeeping.business.book.model.Do.BookDo;
import com.qp.bookkeeping.business.book.model.Do.ColumnDo;
import com.qp.bookkeeping.business.book.model.Do.ShareGroupDo;
import com.qp.bookkeeping.business.book.model.Do.UserDo;
import com.qp.bookkeeping.business.book.model.Dto.BookDto;
import com.qp.bookkeeping.business.book.model.Dto.ShareGroupDto;
import com.qp.bookkeeping.business.book.model.Dto.UserDto;
import com.qp.bookkeeping.business.book.model.businessEnum.BookType;
import com.qp.bookkeeping.business.book.model.req.*;
import com.qp.bookkeeping.business.book.model.rsp.QueryBookRsp;
import com.qp.bookkeeping.business.book.model.rsp.StatisticMonthRsp;
import com.qp.bookkeeping.business.book.service.BookService;
import com.qp.bookkeeping.business.common.Exception.BusinessException;
import com.qp.bookkeeping.common.model.rsp.BusinessExceptionEnum;
import com.qp.bookkeeping.common.utils.DatabasesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xutianqi
 */
@Service
@Slf4j
public class BookServiceImpl implements BookService {
    @Resource
    DatabasesUtil databasesUtil;

    @Resource
    BookMapper bookMapper;

    @Resource
    UserMapper userMapper;

    @Resource
    ColumnMapper columnMapper;

    @Override
    public void bookkeeping(SaveBookReq saveBookReq) {
        long snowflakeId = databasesUtil.snowflakeId();
        String id = String.valueOf(snowflakeId);
        BookDo bookDo = saveBookReq.getBookDo();
        bookDo.setId(id);
        String creatorPhone = bookDo.getCreatorPhone();
        bookDo.setCreatorPhone(creatorPhone);
        bookDo.setUpdaterPhone(creatorPhone);
        if (saveBookReq.getBookType() == BookType.INCOME) {
            bookMapper.insertIncome(bookDo);
        } else if (saveBookReq.getBookType() == BookType.EXPENDITURE) {
            bookMapper.insertExpenditure(bookDo);
        }
        System.out.println(JSONUtil.toJsonStr(bookDo));
    }

    /**
     * 查账
     *
     * @param queryBookReq 查账req
     * @return 返回体
     */
    @Override
    public QueryBookRsp queryBook(QueryBookReq queryBookReq) {
        log.info("queryBook入参：" + JSONUtil.toJsonStr(queryBookReq));
        // 填充查询全体共享组成员时的req
        fillQueryGroupReq(queryBookReq);

        List<QueryBookBo> queryBookBos;
        switch (queryBookReq.getBookType()) {
            case INCOME:
                queryBookBos = bookMapper.selectIncome(queryBookReq);
                break;
            case EXPENDITURE:
                queryBookBos = bookMapper.selectExpenditure(queryBookReq);
                break;
            default:
                queryBookBos = bookMapper.selectAllBook(queryBookReq);
                break;
        }

        fillColumnName(queryBookBos);
        fillUserNickName(queryBookBos);
        return QueryBookRsp.builder().queryBookBos(queryBookBos).build();
    }

    /**
     * 按月统计
     *
     * @return 月统计数据
     */
    @Override
    public StatisticMonthRsp statisticMonth(StatisticMonthReq statisticMonthReq) {
        String phoneNumber = filterPhoneNumber(statisticMonthReq);
        // 根据手机号统计月数据
        LocalDate today = LocalDate.now();
        int year = today.getYear();
        int month = today.getMonthValue();
        List<StatisticMonthBo> statisticMonthBos = bookMapper.statisticMonth(BookDto.builder().creatorPhone(phoneNumber)
                .year(String.valueOf(year))
                .month(String.valueOf(month)).build());
        if (CollectionUtils.isEmpty(statisticMonthBos)) {
            throw new BusinessException(BusinessExceptionEnum.NULL_DATA);
        }

        StatisticMonthRsp statisticMonthRsp = StatisticMonthRsp.builder().build();
        for (StatisticMonthBo statisticMonthBo : statisticMonthBos) {
            if (BookType.EXPENDITURE.getName().equals(statisticMonthBo.getBookType())) {
                statisticMonthRsp.setExpenditure(statisticMonthBo.getSum());
            } else {
                statisticMonthRsp.setIncome(statisticMonthBo.getSum());
            }
        }
        return statisticMonthRsp;
    }

    /**
     * 删除一条账单记录
     *
     * @param deleteBookReq 请求体
     */
    @Override
    public void deleteBookById(DeleteBookReq deleteBookReq) {
        BookDto bookDto = BookDto.builder().id(deleteBookReq.getId()).build();
        if (deleteBookReq.getBookType() == BookType.EXPENDITURE) {
            bookMapper.deleteExpenditureById(bookDto);
        } else {
            bookMapper.deleteIncomeById(bookDto);
        }
    }

    private String filterPhoneNumber(StatisticMonthReq statisticMonthReq) {
        String phoneNumber = statisticMonthReq.getPhoneNumber();
        if (!StringUtils.isBlank(phoneNumber)) {
            return phoneNumber;
        }
        String hwOpenId = statisticMonthReq.getHwOpenId();
        if (!StringUtils.isBlank(hwOpenId)) {
            List<UserDo> userDos = userMapper.selectUsers(UserDto.builder().hwOpenIds(Lists.newArrayList(hwOpenId)).build());
            if (CollectionUtils.isEmpty(userDos)) {
                throw new BusinessException("openId:" + hwOpenId + "  该用户不存在！");
            } else {
                // 根据手机号统计
                phoneNumber = userDos.get(0).getPhoneNumber();
                return phoneNumber;
            }
        }
        return phoneNumber;
    }

    private void fillUserNickName(List<QueryBookBo> queryBookBos) {
        if (CollectionUtils.isEmpty(queryBookBos)) {
            return;
        }
        Set<String> phoneSet = new HashSet<>();
        queryBookBos.forEach(e -> {
            phoneSet.add(e.getCreatorPhone());
            phoneSet.add(e.getUpdaterPhone());
        });

        List<UserDo> userDos = userMapper.selectUsers(UserDto.builder().phoneNumbers(phoneSet.stream().collect(Collectors.toList())).build());
        Map<String, String> phoneNameMap = Optional.ofNullable(userDos).orElse(Lists.newArrayList()).stream().collect(Collectors.toMap(UserDo::getPhoneNumber, UserDo::getNickName, (v1, v2) -> v1));
        queryBookBos.forEach(e -> {
            e.setCreatorName(phoneNameMap.get(e.getCreatorPhone()));
            e.setUpdaterName(phoneNameMap.get(e.getUpdaterPhone()));
        });
    }

    private void fillQueryGroupReq(QueryBookReq queryBookReq) {
        if (!queryBookReq.getIsGroup()) {
            return;
        }
        List<String> groupIds = queryBookReq.getGroupIds();
        if (CollectionUtils.isEmpty(groupIds)) {
            throw new BusinessException("查询共享组全员，groupIds为空");
        }
        List<ShareGroupDo> shareGroupDos = userMapper.selectGroups(ShareGroupDto.builder().groupIds(groupIds).build());
        if (CollectionUtils.isEmpty(shareGroupDos)) {
            throw new BusinessException("未查到共享组信息");
        }
        Set<String> phoneNumbers = new HashSet<>();
        shareGroupDos.forEach(e -> {
            phoneNumbers.add(e.getInitiatorPhone());
            phoneNumbers.add(e.getMemberPhone());
        });
        queryBookReq.setCreatorPhones(new ArrayList<>(phoneNumbers));
    }

    private void fillColumnName(List<QueryBookBo> queryBookBos) {
        if (CollectionUtils.isEmpty(queryBookBos)) {
            return;
        }
        List<String> firstColumnCodes = queryBookBos.stream().map(QueryBookBo::getFirstColumnCode).distinct().collect(Collectors.toList());
        List<String> secondColumnCodes = queryBookBos.stream().map(QueryBookBo::getSecondColumnCode).distinct().collect(Collectors.toList());
        List<String> columnCodes = new ArrayList<>();
        columnCodes.addAll(firstColumnCodes);
        columnCodes.addAll(secondColumnCodes);
        columnCodes = columnCodes.stream().distinct().collect(Collectors.toList());
        List<ColumnDo> columnDos = columnMapper.selectColumns(QueryColumnReq.builder().columnCodes(columnCodes).build());
        if (CollectionUtils.isEmpty(columnDos)) {
            return;
        }
        Map<String, String> codeNameMap = columnDos.stream().collect(Collectors.toMap(ColumnDo::getColumnCode, ColumnDo::getColumnName, (v1, v2) -> v2));
        queryBookBos.forEach(bookBo -> bookBo.setFirstColumnName(codeNameMap.get(bookBo.getFirstColumnCode())));
        queryBookBos.forEach(bookBo -> bookBo.setSecondColumnName(codeNameMap.get(bookBo.getSecondColumnCode())));
    }
}
